package com.quwan.app.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.quwan.app.service.MemberService;
import com.quwan.app.service.OrderService;
import com.quwan.app.service.PrePaymentInterface;
import com.quwan.app.service.ProductCategoryService;
import com.quwan.app.vo.*;
import com.quwan.app.vo.pay.*;
import com.quwan.common.BaseService;
import com.quwan.common.Check;
import com.quwan.common.ImMsgType;
import com.quwan.common.WeekTips;
import com.quwan.common.enums.*;
import com.quwan.common.exception.ExpCode;
import com.quwan.common.exception.ResponseException;
import com.quwan.common.exception.ServiceException;
import com.quwan.common.result.PageResult;
import com.quwan.component.AsyncTaskComponent;
import com.quwan.component.TencentComponent;
import com.quwan.config.yml.ImConfig;
import com.quwan.config.yml.OssConfig;
import com.quwan.config.yml.PaymentBalanceConfig;
import com.quwan.constans.AppConst;
import com.quwan.constans.CacheKey;
import com.quwan.entity.*;
import com.quwan.manager.controller.dto.OrderDTO;
import com.quwan.mapper.*;
import com.quwan.utils.DateUtils;
import com.quwan.utils.NumberUtils;
import com.quwan.utils.Parse;
import com.quwan.utils.PayUtil;
import com.quwan.utils.redis.Redis;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicLong;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @author quan
 * @date 2021-06-10 15:49
 */
@Service
@RequiredArgsConstructor
public class OrderServiceImpl extends BaseService implements OrderService {

    @Value("${spring.profiles.active}")
    private String env;
    @Value("${msg.process.chatMsg}")
    private String chatMsg;
    @Value("${msg.orderComment}")
    private String orderComment;
    private final TPublishOrderMapper publishOrderMapper;
    private final C2cOrderMapper orderMapper;
    private final C2cOrderItemMapper orderItemMapper;
    private final TPublishOrderImgMapper publishOrderImgMapper;
    private final TOrderCommentMapper orderCommentMapper;
    private final TMemberMapper memberMapper;
    private final TOrderSplitMapper orderSplitMapper;
    private final C2cOrderCancelMapper orderCancelMapper;
    private final TMemberBalanceLogMapper memberBalanceLogMapper;
    private final AsyncTaskComponent taskComponent;
    private final TProductCategoryMapper categoryMapper;
    private final TSpreadSettingMapper tSpreadSettingMapper;
    private final TDdLogMapper ddLogMapper;
    private final TCollectOrderMapper collectOrderMapper;
    private final TDispatchOrderApplyMapper applyMapper;
    private final TDispatchOrderMapper dispatchOrderMapper;
    private final TPublishCategoryMapper publishCategoryMapper;

    private final Redis redis;
    private final OssConfig ossConfig;
    private final PaymentBalanceConfig balanceConfig;
    private final TScaleSettingMapper scaleSettingMapper;
    private final ImConfig imConfig;
    @Autowired
    private MemberService memberService;
    @Autowired
    private ProductCategoryService productCategoryService;
    @Autowired
    @Qualifier("asyncThread")
    private ThreadPoolTaskExecutor executor;
    @Autowired
    private TencentComponent tencentComponent;


    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    @Override
    public boolean memberPublishOrder(PublishOrderVo params) {
        String publishId = IdWorker.getIdStr();
        List<String> timeList =
                params
                        .getTimeLimit()
                        .stream()
                        .filter(f -> Pattern.matches(AppConst.PUBLISH_ORDER_TIME, f))
                        .collect(Collectors.toList());
        List<TProductCategory> productCategories = categoryMapper.selectList(
                new LambdaQueryWrapper<TProductCategory>()
                        .in(TProductCategory::getId, params.getCategoryId())
                        .select(TProductCategory::getId, TProductCategory::getCaption, TProductCategory::getOwner)
        );
        Long categoryId = CollectionUtils.isEmpty(productCategories) ? 0L : productCategories.get(0).getOwner();

        TPublishOrder publishOrder = new TPublishOrder();
        BeanUtils.copyProperties(params, publishOrder);
        publishOrder.setId(publishId);
        publishOrder.setCategoryId(categoryId);
        publishOrder.setCityName(params.getCityName());
        publishOrder.setTimeLimit(listToStr(timeList));

        List<TPublishCategory> cates = productCategories.stream().map(m -> new TPublishCategory().setCName(m.getCaption()).setCId(m.getId()).setOwner(m.getOwner()).setPId(Parse.toLong(publishId))).collect(Collectors.toList());
        publishCategoryMapper.insertBatchSomeColumn(cates);

        if (StringUtils.isNotBlank(params.getImgs()))
            publishOrderImgMapper.insertBatchSomeColumn(
                    Arrays
                            .stream(params.getImgs().split(","))
                            .filter(StringUtils::isNotBlank)
                            .limit(AppConst.order.publish_img_max)
                            .map(m ->
                                    new TPublishOrderImg()
                                            .setUrl(StringUtils.isBlank(m) ? m : m.replace(ossConfig.getHostname() + "/", ""))
                                            .setPublishOrderId(Long.parseLong(publishId))
                                            .setAddTime(new Date())
                            )
                            .collect(Collectors.toList()));

        return publishOrderMapper.insert(publishOrder) == 1;
    }

    @Override
    public PageResult<PublishOrderSimple> appPublishOrderList(int pageNo, int pageSize,
                                                              BigDecimal lat, BigDecimal lng,
                                                              String categoryId, String type, String autoWhere,
                                                              String priceDesc, Integer age, String cityName,
                                                              String cityCode, String gender, String parentCate, String keyword) {

//        boolean isCache = pageNo <= 1
//                &&
//                StringUtils.isBlank(categoryId) &&
//                StringUtils.isBlank(autoWhere) &&
//                StringUtils.isBlank(priceDesc) &&
//                age == null &&
//                StringUtils.isBlank(cityName) &&
//                StringUtils.isBlank(cityCode) &&
//                StringUtils.isBlank(gender) &&
//                StringUtils.isBlank(parentCate) &&
//                StringUtils.isBlank(keyword);
//        if (isCache){
//            Object o = redis.get(CacheKey.DATA.indexPublishOrder);
//
//        }

            if (StringUtils.isNotBlank(keyword))
                keyword = keyword.trim();
            else keyword = null;
        Page<Map<String, Object>> publishOrders =
                publishOrderMapper
                        .getPublishOrderBaseInfoWithDistance(
                                new Page<>(pageNo, pageSize), lat, lng, categoryId, type, autoWhere, priceDesc, age, cityName, cityCode, gender, parentCate, keyword);
        return new PageResult<PublishOrderSimple>()
                .setCurrent(publishOrders.getCurrent())
                .setTotal(publishOrders.getTotal())
                .setPages(publishOrders.getPages())
                .setSize(publishOrders.getSize())
                .setRecords(
                        publishOrders
                                .getRecords()
                                .stream()
                                .map(m -> {
                                            Map<String, String> map = Maps.transformEntries(m, (k, v) -> String.valueOf(v));
                                            String id = map.get("id");
                                            //  Map<String, String> identityInfo = DateUtils.computeYearAndConstellation(map.get("identity"));
                                            return new PublishOrderSimple()
                                                    .setMId(map.get("m_id"))
                                                    .setPublishOrderId(id)
                                                    //   .setDistance(map.get("distance"))
                                                    .setOtherDesc(map.get("other_desc"))
                                                    .setPrice(new BigDecimal(map.get("price")).intValue() + "")
                                                    .setUnit(map.get("unit"))
                                                    //   .setDistance(map.get("distance"))
                                                    .setImgs(strToList(",", String.valueOf(m.get("imgs")))
                                                            .stream()
                                                            .filter(StringUtils::isNotBlank)
                                                            .map(url -> ossConfig.getHostname() + "/" + url).collect(Collectors.toList()))
                                                    //    .setShowColor(map.get("show_color"))
                                                    //   .setCategory(map.get("caption"))
                                                    .setNickName(map.get("nick_name"))
                                                    .setImageUrl(StringUtils.isBlank(map.get("img_url")) ? "" : ossConfig.getHostname() + "/" + map.get("img_url"))
                                                    .setServiceLevel(map.get("service_level"))
                                                    .setArea(StringUtils.isBlank(map.get("city_name")) ? parseArea(map.get("area")) : map.get("city_name"))
                                                    .setOnline(DateUtils.computeOnlineTime(DateUtils.localDateTimeOfStr(String.valueOf(map.get("last_visit_time")))))
                                                    //.setYear(identityInfo.get("year"))
                                                    .setIdBoolean(Parse.toInt(map.get("id_status"), 0) > 0)
                                                    .setVip(Parse.toInt(map.get("v"), 0) > 0);
                                            //.setConstellation(identityInfo.get("constellation"));
                                        }
                                )
                                //.sorted(Comparator.comparing(PublishOrderSimple::getDistance))
                                .collect(Collectors.toList())
                );
    }

    @Override
    public PublishOrderSimple getPublishOrderDetails(String mId, String publishOrderId) {
        recordHistory(mId, publishOrderId);
        Map<String, Object> map =
                publishOrderMapper
                        .selectPublishOrderBaseInfo(publishOrderId);
        Check.notNull(map, ExpCode.ORDER_NOT_EXIST);

        List<TPublishCategory> categoryList = publishCategoryMapper.selectList(new QueryWrapper<>(new TPublishCategory().setPId(Parse.toLong(publishOrderId))));
        Map<String, String> res = Maps.transformEntries(map, (k, v) -> String.valueOf(v));
        return new PublishOrderSimple()
                .setCollectButton(!res.get("m_id").equals(mId))
                .setCollect(StringUtils.isNotBlank(mId) &&
                        collectOrderMapper
                                .selectCount(new LambdaQueryWrapper<TCollectOrder>()
                                        .eq(TCollectOrder::getUnLock, mId + publishOrderId)
                                        .eq(TCollectOrder::getStatus, CommonStatus.NORMAL.getType()))
                                == 1)
                .setNickName(res.get("nick_name"))
                .setMId(res.get("m_id"))
                .setImageUrl(ossConfig.getHostname() + "/" + res.get("img_url"))
                .setOtherDesc(res.get("other_desc"))
                .setArea(StringUtils.isBlank(res.get("city_name")) ? parseArea(res.get("area")) : res.get("city_name"))
                .setShowColor(res.get("show_color"))
                .setCategory(res.get("caption"))
                .setCategoryId(res.get("category_id"))
                .setPublishOrderId(res.get("id"))
                .setMId(res.get("m_id"))
                .setPrice(res.get("price"))
                .setAgeLimit(res.get("age_limit"))
                .setGender(res.get("gender_limit"))
                .setUnit(res.get("unit"))
                .setVisitCount(redis.hIncrBy(CacheKey.DATA.publishOrderVisit, publishOrderId, 1))
                .setServiceLevel(res.get("service_level"))
                .setCategoryList(categoryList)
                .setImgs(strToList(",", res.get("imgs")).stream().filter(StringUtils::isNotBlank).map(m -> ossConfig.getHostname() + "/" + m).collect(Collectors.toList()))
                .setTime(strToList(",", res.get("time_limit"))
                        .stream()
                        .filter(f -> Pattern.matches(AppConst.PUBLISH_ORDER_TIME, f))
                        .map(m -> {
                                    //时间规则 1_16:00-18:00  开始是周数
                                    String[] timeRule = m.split("_");
                                    return new SelectorWeekVo()
                                            .setTime(timeRule[1])
                                            .setTips(WeekTips.getStr(Integer.valueOf(timeRule[0])))
                                            .setWeek(timeRule[0]);
                                }
                        )
                        .sorted(Comparator.comparing(SelectorWeekVo::getWeek))
                        .collect(Collectors.toList())
                );
    }


    @Override
    public BuyItOrderDTO buyIt(String publishOrderId, final String memberId) {
        TPublishOrder publishOrder =
                publishOrderMapper
                        .selectOne(
                                new LambdaQueryWrapper<TPublishOrder>()
                                        .select(TPublishOrder::getMId, TPublishOrder::getTimeLimit, TPublishOrder::getUnit, TPublishOrder::getPrice, TPublishOrder::getCategoryId)
                                        .eq(TPublishOrder::getId, publishOrderId)

                        );
        Check.notNull(publishOrder, ExpCode.DATA_SELECT_NULL);
        Check.state(!memberId.equals(String.valueOf(publishOrder.getMId())), ExpCode.NOT_BUY_SELF);

        //查询发单人 所有发单id
        String publishOrderIds =
                publishOrderMapper
                        .selectList(
                                new LambdaQueryWrapper<TPublishOrder>()
                                        .select(TPublishOrder::getId)
                                        .eq(TPublishOrder::getMId, publishOrder.getMId())
                        )
                        .stream()
                        .filter(f -> StringUtils.isNotBlank(f.getId()))
                        .map(TPublishOrder::getId)
                        .collect(Collectors.joining(","));

        final BuyItOrderDTO res = new BuyItOrderDTO();
        CompletableFuture<List<SelectorWeekVo>> itemAsync =
                CompletableFuture
                        .supplyAsync(() -> {
                                    String timeLimit = publishOrder.getTimeLimit();
                                    //转换规则是 key = categoryId value = TProductCategory
                                    ImmutableMap<Long, TProductCategory> cates = Maps.uniqueIndex(categoryMapper.selectAll(), TProductCategory::getId);
                                    TProductCategory cate = cates.get(publishOrder.getCategoryId());
                                    res.setCategory(Optional.ofNullable(cate).map(TProductCategory::getCaption).orElse(""));
                                    return strToList(",", publishOrder.getTimeLimit())
                                            .stream()
                                            .filter(f -> Pattern.matches(AppConst.PUBLISH_ORDER_TIME, f))
                                            .map(m -> {
                                                String[] split = m.split("_");
                                                String[] timeSplit = split[1].split("-");
                                                String week = split[0];
                                                String beginTime = timeSplit[0];
                                                String endTime = timeSplit[1];
                                                Long max = 30L;
                                                LocalTime begin = DateUtils.localTimeOfStr(beginTime);
                                                LocalTime end = DateUtils.localTimeOfStr(endTime);
                                                Integer unit = publishOrder.getUnit();

                                                max = unit == 0 ? begin.isBefore(end) ? Duration.between(begin, end).toHours() : 0 : 1;
                                                String realData = DateUtils.week_DateMap().get(week);
                                                //发单人 当前日期是否存在已接单的订单
                                                //如果预定时间存在未处理订单 判定订单预定时间为关闭
                                                //如果当前时间距离用户发布时间 不超2小时 判定订单预定时间为关闭
                                                Integer count =
                                                        orderMapper
                                                                .selectCountByPublishOrderIdAndDate(StringUtils.isNotBlank(publishOrderIds) ? publishOrderIds : "-1", DateUtils.localDateOfStr(realData));
                                                LocalDateTime realLocalDateTime = LocalDateTime.of(DateUtils.localDateOfStr(realData), begin);
                                                boolean dateLimit = Duration.between(LocalDateTime.now(), realLocalDateTime).toHours() > 2
                                                        && (unit != -1 || !realLocalDateTime.toLocalDate().isEqual(LocalDate.now()));
                                                return new SelectorWeekVo()
                                                        .setTips(WeekTips.getStr(Integer.parseInt(week)))
                                                        .setTime(beginTime)
                                                        .setMax(max)
                                                        .setWeek(week)
                                                        .setRealDate(DateUtils.getLocalDateTimeStr(realLocalDateTime))
                                                        .setSimpleDate(realLocalDateTime.format(DateTimeFormatter.ofPattern("MM-dd")))
                                                        .setStatus(count == 0 && dateLimit ? CommonStatus.NORMAL.getType() : CommonStatus.DISABLED.getType());
                                            })
                                            .sorted(Comparator.comparing(SelectorWeekVo::getRealDate))
                                            .collect(Collectors.toList());
                                },
                                executor);

        String mId = String.valueOf(publishOrder.getMId());
        TMember memberInfo = memberService.getMemberInfoById(mId);
        Check.notNull(memberInfo, ExpCode.DATA_SELECT_NULL);

        //生成消费订单
        TMember consumerMember = memberService.getMemberInfoById(memberId);
        Check.notNull(consumerMember, ExpCode.DATA_SELECT_NULL);
        String c2cOrderId = IdWorker.getIdStr();
        C2cOrder c2cOrder =
                new C2cOrder()
                        .setPublishOrderId(publishOrderId)
                        .setMId(Long.parseLong(memberId))
                        .setId(c2cOrderId)
                        .setContactNumber(consumerMember.getMobile())
                        .setContactName(consumerMember.getNickName())
                        .setProductPrice(publishOrder.getPrice());
        Assert.state(orderMapper.insert(c2cOrder) == 1, "consumer order err");
        try {
            res.setTimeSeletor(itemAsync.get());
        } catch (Exception e) {
            e.printStackTrace();
        }

        return res
                .setId(c2cOrderId)
                .setNickName(memberInfo.getNickName())
                .setImgUrl(memberInfo.getImgUrl())
                .setServiceLevel(memberInfo.getServiceLevel() + "")
                .setPrice(publishOrder.getPrice().toString())
                .setCoupon(computeCouponInfo(consumerMember, AppConst.COUPON_DD.toString()))
                .setUnit(publishOrder.getUnit() + "");
    }

    /**
     * 计算优惠信息   null 无优惠
     *
     * @return
     */
    private Coupon computeCouponInfo(TMember member, String couponType) {
        if (member == null || StringUtils.isBlank(couponType)) return null;
        else if (AppConst.COUPON_DD.toString().equals(couponType)) {
            String mId = member.getId().toString();
            Integer memberDD = member.getDd();
            //当天没有使用优惠 进行优惠计算
            if (checkCoupon(mId) == null) {
                if (memberDD != 0 && memberDD > 0) {
                    Coupon coupon =
                            new Coupon()
                                    .setCouponType(AppConst.COUPON_DD.toString())
                                    .setTotal(memberDD);
                    //限制使用最大数量
                    if (memberDD > AppConst.MAX_COUPON_DD)
                        coupon
                                .setDeduct(AppConst.MAX_COUPON_DD)
                                .setCouponPrice(
                                        new BigDecimal(AppConst.MAX_COUPON_DD)
                                                .divide(
                                                        AppConst.b100,
                                                        2,
                                                        BigDecimal.ROUND_HALF_UP)
                                );
                    else
                        coupon
                                .setDeduct(memberDD)
                                .setCouponPrice(
                                        new BigDecimal(memberDD)
                                                .divide(
                                                        AppConst.b100,
                                                        BigDecimal.ROUND_HALF_UP));

                    return coupon;
                }

            }
        }

        return null;
    }

    /**
     * 检查会员当天是否有进行过优惠
     *
     * @param mId
     * @return
     */
    private TDdLog checkCoupon(String mId) {
        return ddLogMapper.selectOne(new LambdaQueryWrapper<TDdLog>()
                .select(TDdLog::getDd)
                .eq(TDdLog::getMId, mId)
                .eq(TDdLog::getType, AppConst.COUPON_DD)
                .eq(TDdLog::getDay, LocalDate.now())
        );
    }


    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    @Override
    public PrePayment payOrder(final String mId, BuyItParams params, PrePaymentInterface paymentInterface) {
        //删除 订单附加信息
        C2cOrderItem del = new C2cOrderItem().setC2cOrderId(params.getConsumeOrderId());
        orderItemMapper.delete(new QueryWrapper<>(del));
        //查询未支付订单信息
        C2cOrder order =
                orderMapper
                        .selectOne(
                                new LambdaQueryWrapper<C2cOrder>()
                                        .select(C2cOrder::getAutoId, C2cOrder::getId, C2cOrder::getPublishOrderId)
                                        .eq(C2cOrder::getId, params.getConsumeOrderId())
                                        .eq(C2cOrder::getMId, mId)
                                        .eq(C2cOrder::getPayStatus, PayStatusEnum.NOT.getType())
                        );
        Check.notNull(order, ExpCode.ORDER_NOT_EXIST);
        //发单信息
        TPublishOrder publishOrder =
                publishOrderMapper
                        .selectOne(
                                new LambdaQueryWrapper<TPublishOrder>()
                                        .select(TPublishOrder::getUnit, TPublishOrder::getPrice, TPublishOrder::getCategoryId, TPublishOrder::getId)
                                        .eq(TPublishOrder::getId, order.getPublishOrderId())

                        );
        Check.notNull(publishOrder, ExpCode.ORDER_NOT_EXIST);

        Integer unit = publishOrder.getUnit();
        if (unit == -1)
            params.setAmount(1);
        TProductCategory cate =
                productCategoryService
                        .getProductCategoryById(publishOrder.getCategoryId());
        TMember member = memberService.getMemberInfoById(mId);
        Check.notNull(member, ExpCode.MEMBER_NOT_EXIST);
        C2cOrder c2cOrder = new C2cOrder();
        //当前订单有使用优惠
        if (StringUtils.isNotBlank(params.getCoupon())) {
            // 计算优惠
            Coupon coupon = computeCouponInfo(member, params.getCoupon());
            c2cOrder
                    .setCouponStatus(
                            coupon == null ? CommonStatus.DISABLED.getType()
                                    : coupon.getCouponType() == null ? CommonStatus.DISABLED.getType()
                                    : Integer.parseInt(coupon.getCouponType()))
                    .setCouponPrice(coupon == null ? BigDecimal.ZERO : coupon.getCouponPrice());
        }
        //无优惠订单总价
        BigDecimal totalPrice = publishOrder.getPrice().multiply(new BigDecimal(params.getAmount()));
        //优惠过后订单价格
        BigDecimal payPrice = totalPrice.subtract(c2cOrder.getCouponPrice() == null ? BigDecimal.ZERO : c2cOrder.getCouponPrice());
        String amountByEnv = PayUtil.getPayAmountByEnv(env, payPrice);
        //回调获取预支付参数
        PrePayParams prePayParams =
                new PrePayParams(
                        params.getPayType().equals(PaymentEnum.SYSTEM_PAY.getType()) ? payPrice.toString() : amountByEnv,
                        params.getConsumeOrderId(),
                        cate == null ? "" : cate.getCaption() + " x " + params.getAmount(),
                        PaymentEnum.getByType(params.getPayType()).getOrder(),
                        mId);
        PrePayment prePayInfo = paymentInterface.prePayment(prePayParams);
        Assert.notNull(prePayInfo, "undefined payMethod");

        //计算订单开始时间
        LocalDateTime beginTime = DateUtils.localDateTimeOfStr(params.getBeginTime());
        beginTime = beginTime == null ? LocalDateTime.now() : beginTime;
        LocalDateTime endTime = publishOrder.getUnit().equals(0) ?
                beginTime.plusHours(params.getAmount()) :
                beginTime.plusDays(params.getAmount());
        //更新订单的一些支付参数
        c2cOrder
                .setAddress("")
                .setAddressDetail("")
                .setPayMethod(Integer.parseInt(params.getPayType()))
                .setBeginTime(beginTime)
                .setEndTime(endTime)
                .setAmount(params.getAmount())
                .setProductPrice(totalPrice)
                .setPayPrice(payPrice);

        //判断支付类型  设置预支付流水
        if (prePayInfo instanceof WxPrePayment)
            c2cOrder.setPrePayId(((WxPrePayment) prePayInfo).getPrePayId());
        else if (prePayInfo instanceof BalancePrePayment)
            c2cOrder.setPrePayId(((BalancePrePayment) prePayInfo).getPreId());

        Assert.state(
                orderMapper
                        .update(c2cOrder,
                                new LambdaUpdateWrapper<C2cOrder>()
                                        .eq(C2cOrder::getAutoId, order.getAutoId())) == 1,
                "update prepayInfo err"
        );

        Assert.state(orderItemMapper
                        .insert(
                                new C2cOrderItem()
                                        .setC2cOrderId(params.getConsumeOrderId())
                                        .setAmount(params.getAmount())
                                        .setPrice(publishOrder.getPrice())
                                        .setTips(cate == null ? "" : cate.getCaption())
                                        .setPublishItemId("0")
                                        .setShowColor(cate == null ? "" : cate.getShowColor())
                                        .setUnit(publishOrder.getUnit())) == 1
                , "C2cOrderItem save error ");
        //当前订单是否有使用优惠
        if (c2cOrder.getCouponPrice() != null && c2cOrder.getCouponPrice().compareTo(BigDecimal.ZERO) > 0) {
            //有优惠 进行优惠扣除
            Integer consumeDD = c2cOrder.getCouponPrice().multiply(AppConst.b100).intValue();
            int row = memberMapper
                    .update(
                            null,
                            new LambdaUpdateWrapper<TMember>()
                                    .set(TMember::getVersion, member.getVersion() + 1)
                                    .set(TMember::getDd, member.getDd() - consumeDD)
                                    .eq(TMember::getId, mId)
                                    .eq(TMember::getVersion, member.getVersion())
                    );
            if (row == 1) {
                // orderid 加入缓存 5-10分钟未支付优惠的订单    5-10分钟随机删除改订单 过期优惠订单事件监听 优惠道具返回会员
                redis.setListener(RedisListenerEnum.cancel_coupon_order.getKey() + RedisListenerEnum.split + params.getConsumeOrderId(),
                        0,
                        NumberUtils.randomScopeNum(AppConst.order.expire_min, AppConst.order.expire_max).longValue());
            }
        }

        return prePayInfo;
    }

    public static final AtomicLong handle_order_count = new AtomicLong(0);
    @Value("${msg.process.content}")
    private String processContent;

    @Transactional
    @Override
    public boolean changeC2cOrderStatusById(String mId, String orderId) {
        //查询订单信息
        C2cOrder order =
                orderMapper
                        .selectOne(
                                new LambdaQueryWrapper<C2cOrder>()
                                        .select(C2cOrder::getPublishOrderId, C2cOrder::getOrderStatus, C2cOrder::getMId, C2cOrder::getBeginTime)
                                        .eq(C2cOrder::getId, orderId)
                        );
        Check.notNull(order, ExpCode.ORDER_NOT_EXIST);
        //查询发单信息
        TPublishOrder publishOrder = publishOrderMapper
                .selectOne(
                        new LambdaQueryWrapper<TPublishOrder>()
                                .select(TPublishOrder::getMId)
                                .eq(TPublishOrder::getId, order.getPublishOrderId())
                );
        Check.notNull(publishOrder, ExpCode.ORDER_NOT_EXIST);
        //检查 接单请求人 是否是该订单发单人
        if (!mId.equals(String.valueOf(publishOrder.getMId())))
            return false;
        int row = orderMapper.update(
                null,
                new LambdaUpdateWrapper<C2cOrder>()
                        .set(C2cOrder::getOrderStatus, AppConst.ORDER_HANDLE)
                        .eq(C2cOrder::getId, orderId)
        );
        if (row == 1) {
            redis.delStrKey(RedisListenerEnum.cancel_not_process_order.getKey() + RedisListenerEnum.split + orderId);
            //订单自动确认完成
            //  _computeAutoConfirm(orderId, order.getBeginTime());
            //当天接单人加1
            handle_order_count.incrementAndGet();
            //type 1 查询的是发单人信息
            PushOfflineMsgParams params = pushOffLineMsg(order.getMId(), AppConst.CAT_SERVICE_TYPE, orderId, memberService.getNickNameById(publishOrder.getMId()), processContent, AppConst.OFFLINE_MSG_ORDER_ORDER_HANDLE);
            //接单消息通知下单人
            try {
                taskComponent.pushOfflineMsgToMember(params);
                tencentComponent
                        .singlePushMsg(1, mId,
                                order.getMId().toString(),
                                order.getMId().toString(), ImMsgType.text.getCode(), chatMsg);
            } catch (Exception e) {
                logger.info("pushOfflineMsgToMember exp::{}", e.getMessage());
            }
            return true;
        } else
            throw new ResponseException(ExpCode.DB_UPDATE_ERR.getCode(), ExpCode.DB_UPDATE_ERR.getMsg());

    }

    private void _computeAutoConfirm(String orderId, LocalDateTime beginTime) {
        LocalDateTime now = LocalDateTime.now();
        if (StringUtils.isBlank(orderId) || beginTime == null || now.isAfter(beginTime))
            return;
        Long second = DateUtils.computeSecond(now, beginTime.plusHours(balanceConfig.getAutoConfirm()));
        //   redis.setListener(RedisListenerEnum.auto_confirm_order.getKey() + RedisListenerEnum.split + orderId, 0, second);
    }

    @Override
    public PageResult<PublishOrderSimple> memberPublishOrderList(int pageNo, int pageSize, String memberId, Integer status) {
        Page<TPublishOrder> publishOrderPage =
                publishOrderMapper
                        .selectPage(
                                new Page<>(pageNo, pageSize),
                                new LambdaQueryWrapper<TPublishOrder>()
                                        .select(TPublishOrder::getId, TPublishOrder::getOtherDesc, TPublishOrder::getMId, TPublishOrder::getAreaLimit, TPublishOrder::getUnit, TPublishOrder::getPrice, TPublishOrder::getCategoryId, TPublishOrder::getAddTime, TPublishOrder::getCityName)
                                        .eq(TPublishOrder::getMId, memberId)
                                        .eq(TPublishOrder::getStatus, status)
                                        .orderByDesc(TPublishOrder::getAddTime)
                        );
        List<String> ids = publishOrderPage
                .getRecords()
                .stream()
                .map(TPublishOrder::getId)
                .collect(Collectors.toList());
        if (CollectionUtils.isEmpty(ids))
            return new PageResult<>();
        Map<Long, List<TPublishOrderImg>> imgs = publishOrderImgMapper
                .selectList(
                        new LambdaQueryWrapper<TPublishOrderImg>()
                                .select(TPublishOrderImg::getPublishOrderId, TPublishOrderImg::getUrl)
                                .in(TPublishOrderImg::getPublishOrderId, ids)
                )
                .stream()
                .collect(Collectors.groupingBy(TPublishOrderImg::getPublishOrderId));
        TMember memberInfo = memberService.getMemberInfoById(memberId);
        // key = categoryid value =  TProductCategory
        ImmutableMap<Long, TProductCategory> cateMap =
                Maps.uniqueIndex(categoryMapper.selectAll(), TProductCategory::getId);
        return new PageResult<PublishOrderSimple>()
                .setSize(publishOrderPage.getSize())
                .setCurrent(publishOrderPage.getCurrent())
                .setTotal(publishOrderPage.getTotal())
                .setPages(publishOrderPage.getPages())
                .setRecords(
                        publishOrderPage
                                .getRecords()
                                .stream()
                                .map(m ->
                                        new PublishOrderSimple()
                                                .setPublishOrderId(m.getId())
                                                .setOtherDesc(m.getOtherDesc())
                                                .setArea(m.getCityName())
                                                .setMId(memberInfo.getId() + "")
                                                .setNickName(memberInfo.getNickName())
                                                .setImageUrl(memberInfo.getImgUrl())
                                                .setServiceLevel(memberInfo.getServiceLevel() + "")
                                                .setPrice(m.getPrice().toString())
                                                .setUnit(m.getUnit() + "")
                                                .setDate(DateUtils.getLocalDateTimeStr(m.getAddTime(), "MM-dd HH:mm"))
                                                .setShowColor(cateMap.get(m.getCategoryId()) == null ? "" : cateMap.get(m.getCategoryId()).getShowColor())
                                                .setCategory(cateMap.get(m.getCategoryId()) == null ? "" : cateMap.get(m.getCategoryId()).getCaption())
                                                .setImgs(imgs.get(Long.parseLong(m.getId())) == null ? Lists.newArrayList() :
                                                        imgs.get(Long.parseLong(m.getId()))
                                                                .stream()
                                                                .filter(f -> StringUtils.isNotBlank(f.getUrl()))
                                                                .map(url -> ossConfig.getHostname() + "/" + url.getUrl())
                                                                .collect(Collectors.toList())
                                                )

                                )
                                .collect(Collectors.toList())
                );

    }

    @Override
    public PageResult<PublishOrderInfo> memberServiceOrderList(int pageNo, int pageSize, String memberId, Integer status) {
        List<TPublishOrder> publishOrder =
                publishOrderMapper
                        .selectList(
                                new QueryWrapper<>(
                                        new TPublishOrder()
                                                .setMId(Long.parseLong(memberId)))
                        );

        if (CollectionUtils.isEmpty(publishOrder)) return new PageResult<>();

        List<String> ids =
                publishOrder
                        .stream()
                        .map(TPublishOrder::getId)
                        .collect(Collectors.toList());

        Page<C2cOrder> result =
                orderMapper
                        .selectPage(new Page<>(pageNo, pageSize),
                                new LambdaQueryWrapper<C2cOrder>()
                                        .select(C2cOrder::getBeginTime, C2cOrder::getPayPrice, C2cOrder::getId, C2cOrder::getMId, C2cOrder::getPayTime, C2cOrder::getPublishOrderId)
                                        .in(C2cOrder::getPublishOrderId, ids)
                                        .eq(C2cOrder::getPayStatus, PayStatusEnum.FINISH.getType())
                                        .eq(C2cOrder::getOrderStatus, status)
                                        .orderByDesc(C2cOrder::getPayTime)
                        );
        //下单人ids
        List<Long> mIds =
                result
                        .getRecords()
                        .stream()
                        .map(C2cOrder::getMId)
                        .collect(Collectors.toList());
        // 查询 ids 的信息
        List<TMember> members = CollectionUtils.isEmpty(mIds) ? Lists.newArrayList() :
                memberMapper
                        .selectList(
                                new LambdaQueryWrapper<TMember>()
                                        .select(TMember::getId, TMember::getNickName, TMember::getImgUrl, TMember::getServiceLevel, TMember::getArea)
                                        .in(TMember::getId, mIds)
                        );
        //消费订单 ids
        List<String> orderIds = result
                .getRecords()
                .stream()
                .map(C2cOrder::getId)
                .collect(Collectors.toList());

        List<C2cOrderItem> c2cOrderItems = CollectionUtils.isEmpty(orderIds) ? Lists.newArrayList() :
                orderItemMapper
                        .selectList(
                                new LambdaQueryWrapper<C2cOrderItem>()
                                        .select(C2cOrderItem::getC2cOrderId, C2cOrderItem::getShowColor, C2cOrderItem::getTips)
                                        .in(C2cOrderItem::getC2cOrderId, orderIds)
                        );
        // key = mId value = TMember
        ImmutableMap<Long, TMember> mMaps = Maps.uniqueIndex(members, TMember::getId);
        ImmutableMap<String, C2cOrderItem> itemMaps = Maps.uniqueIndex(c2cOrderItems, C2cOrderItem::getC2cOrderId);
        ImmutableMap<String, TPublishOrder> publishOrderMaps = Maps.uniqueIndex(publishOrder, TPublishOrder::getId);
        return new PageResult<PublishOrderInfo>()
                .setSize(result.getSize())
                .setTotal(result.getTotal())
                .setPages(result.getPages())
                .setCurrent(result.getCurrent())
                .setRecords(
                        result
                                .getRecords()
                                .stream()
                                .map(m -> {
                                    TMember memberInfo = Optional.ofNullable(mMaps.get(m.getMId())).orElse(new TMember());
                                    C2cOrderItem item = Optional.ofNullable(itemMaps.get(m.getId())).orElse(new C2cOrderItem());
                                    TPublishOrder po = Optional.ofNullable(publishOrderMaps.get(m.getPublishOrderId())).orElse(new TPublishOrder());
                                    return
                                            new PublishOrderInfo()
                                                    .setShowColor(item.getShowColor())
                                                    .setCategory(item.getTips())
                                                    .setDate(m.getPayTime())
                                                    .setPayPrice(m.getPayPrice())
                                                    .setConsumeOrderId(m.getId())
                                                    .setOtherDesc(po.getOtherDesc())
                                                    .setMId(memberInfo.getId() + "")
                                                    .setNickName(memberInfo.getNickName())
                                                    .setImgUrl(ossConfig.getHostname() + "/" + memberInfo.getImgUrl())
                                                    .setServiceLevel(memberInfo.getServiceLevel() + "")
                                                    .setArea(parseArea(memberInfo.getArea()));

                                })
                                .collect(Collectors.toList())
                );
    }

    @Override
    public PageResult<PublishOrderInfo> memberConsumeOrderList(int pageNo, int pageSize, String memberId, Integer status) {
        //已支付 订单信息
        Page<C2cOrder> c2cOrders =
                orderMapper
                        .selectPage(
                                new Page<>(pageNo, pageSize),
                                new LambdaQueryWrapper<C2cOrder>()
                                        .select(C2cOrder::getId, C2cOrder::getPublishOrderId, C2cOrder::getPayPrice, C2cOrder::getPayTime)
                                        .eq(C2cOrder::getMId, memberId)
                                        .eq(C2cOrder::getPayStatus, PayStatusEnum.FINISH.getType())
                                        .eq(C2cOrder::getOrderStatus, status)
                                        .orderByDesc(C2cOrder::getPayTime)
                        );
        //订单取消
        if (OrderStatusEnum.CANCEL.getStatus().equals(status)) {
            Page<C2cOrderCancel> cancels = orderCancelMapper.selectPage(
                    new Page<>(pageNo, pageSize),
                    new LambdaQueryWrapper<C2cOrderCancel>()
                            .select(C2cOrderCancel::getId, C2cOrderCancel::getPublishOrderId, C2cOrderCancel::getPayPrice, C2cOrderCancel::getPayTime)
                            .eq(C2cOrderCancel::getMId, memberId)
                            .eq(C2cOrderCancel::getPayStatus, PayStatusEnum.FINISH.getType())
                            .orderByDesc(C2cOrderCancel::getPayTime)
            );
            List<C2cOrder> collect = cancels.getRecords().stream().map(m -> {
                C2cOrder order = new C2cOrder();
                BeanUtils.copyProperties(m, order);
                return order;
            }).collect(Collectors.toList());
            c2cOrders.setCurrent(cancels.getCurrent())
                    .setSize(cancels.getSize())
                    .setTotal(cancels.getTotal())
                    .setPages(cancels.getPages())
                    .setRecords(collect);
        }
        // 发单 ids
        List<String> publishIds =
                c2cOrders
                        .getRecords()
                        .stream()
                        .map(C2cOrder::getPublishOrderId)
                        .collect(Collectors.toList());

        if (CollectionUtils.isEmpty(publishIds))
            return new PageResult<>();

        // 发单 ids 信息
        List<TPublishOrder> publishOrders =
                publishOrderMapper
                        .selectList(
                                new LambdaQueryWrapper<TPublishOrder>()
                                        .select(TPublishOrder::getId, TPublishOrder::getOtherDesc, TPublishOrder::getMId,
                                                TPublishOrder::getCategoryId, TPublishOrder::getCityName)
                                        .in(TPublishOrder::getId, publishIds)
                        );
        //发单ids 会员
        List<Long> mIds =
                publishOrders
                        .stream()
                        .map(TPublishOrder::getMId)
                        .collect(Collectors.toList());
        // 查询发单ids 会员 信息

        List<TMember> memberList = CollectionUtils.isEmpty(mIds) ? Lists.newArrayList() :
                memberMapper
                        .selectList(
                                new LambdaQueryWrapper<TMember>()
                                        .select(TMember::getId, TMember::getNickName, TMember::getServiceLevel,
                                                TMember::getArea, TMember::getImgUrl)
                                        .in(TMember::getId, mIds)
                        );

        ImmutableMap<String, TPublishOrder> publishOrderMaps = Maps.uniqueIndex(publishOrders, TPublishOrder::getId);
        ImmutableMap<Long, TMember> mMaps = Maps.uniqueIndex(memberList, TMember::getId);
        ImmutableMap<Long, TProductCategory> cMaps = Maps.uniqueIndex(categoryMapper.selectAll(), TProductCategory::getId);

        return new PageResult<PublishOrderInfo>()
                .setSize(c2cOrders.getSize())
                .setPages(c2cOrders.getPages())
                .setTotal(c2cOrders.getTotal())
                .setCurrent(c2cOrders.getCurrent())
                .setRecords(
                        c2cOrders
                                .getRecords()
                                .stream()
                                .map(m -> {
                                    TPublishOrder publishOrder = publishOrderMaps.get(m.getPublishOrderId());
                                    if (publishOrder == null) return null;
                                    TMember publishMemberInfo = mMaps.get(publishOrder.getMId());
                                    TProductCategory cate = cMaps.get(publishOrder.getCategoryId());
                                    return new PublishOrderInfo()
                                            .setDate(m.getPayTime())
                                            .setPayPrice(m.getPayPrice())
                                            .setConsumeOrderId(m.getId())
                                            .setMId(publishMemberInfo.getId() + "")
                                            .setImgUrl(StringUtils.isBlank(publishMemberInfo.getImgUrl()) ? null : ossConfig.getHostname() + "/" + publishMemberInfo.getImgUrl())
                                            .setServiceLevel(publishMemberInfo.getServiceLevel() + "")
                                            .setNickName(publishMemberInfo.getNickName())
                                            .setOtherDesc(publishOrder.getOtherDesc())
                                            .setCategory(cate == null ? "" : cate.getCaption())
                                            .setShowColor(cate == null ? "" : cate.getShowColor())
                                            .setArea(publishOrder.getCityName());
                                })
                                .collect(Collectors.toList())

                );
    }

    @Override
    public PageResult<OrderDTO> getOrderList(int page, int size,
                                             String orderId, String p_member,
                                             String c_member, String category,
                                             String address, String orderStatus,
                                             String beginTime, String endTime,
                                             String publishBeginTime, String publishEndTime, String publishMemberId, String consumerMemberId) {
        Page<Map<String, Object>> res =
                orderMapper
                        .selectManagerOrderList(new Page<>(page, size),
                                orderId, p_member, c_member, category, address, orderStatus, beginTime, endTime, publishBeginTime, publishEndTime, publishMemberId, consumerMemberId);


        List<OrderDTO> result =
                res
                        .getRecords()
                        .stream()
                        .map(m -> {
                            Map<String, String> map = Maps
                                    .transformEntries(m, (k, v) -> String.valueOf(v));
                            Integer status = Integer.parseInt(map.get("order_status"));
                            Integer refund = Integer.parseInt(map.get("refund_status"));

                            return new OrderDTO()
                                    .setOrderId(map.get("id"))
                                    .setRemarks(map.get("remarks"))
                                    .setAddress(map.get("address_detail"))
                                    .setAddTime(map.get("add_time"))
                                    .setBeginTime(map.get("begin_time"))
                                    .setEndTime(map.get("end_time"))
                                    .setCategory(map.get("cates"))
                                    .setConsumeMember(map.get("c_nick_name"))
                                    .setPublishMember(map.get("p_nick_name"))
                                    .setPublishMemberId(map.get("publish_member_id"))
                                    .setConsumeMemberId(map.get("consumer_member_id"))
                                    .setOrderPrice(map.get("pay_price"))
                                    .setOrderTime(map.get("amount") + ("1".equals(map.get("unit")) ? "天" : "-1".equals(map.get("unit")) ? "一口价" : "小时"))
                                    .setRealMoney(map.get("member_commission"))
                                    .setCompanyCommission(map.get("company_commission"))
                                    .setPopularMoney(map.get("spread_money"))
                                    .setPId(map.get("p_autoId"))
                                    .setCId(map.get("c_autoId"))
                                    .setStatus(status)
                                    .setCancels("4".equals(orderStatus))
                                    .setPopularScale(Optional.ofNullable(map.get("spread_scale")).orElse("0") + "%")
                                    .setOrderStatus(AppConst.ORDER_REFUNDING.equals(refund) ? "申请退款"
                                            : AppConst.ORDER_CANCEL.equals(StringUtils.isBlank(orderStatus) ? "" : Integer.parseInt(orderStatus)) ? "订单取消"
                                            : AppConst.ORDER_REFUND_FINISH.equals(refund) ? "退款完成"
                                            : AppConst.ORDER_AWAIT.equals(status) ? "待接单"
                                            : AppConst.ORDER_HANDLE.equals(status) ? "已接单"
                                            : AppConst.ORDER_CONDUCT.equals(status) ? "进行中"
                                            : AppConst.ORDER_FINISH.equals(status) ? "已完成"
                                            : AppConst.ORDER_BREAK.equals(status) ? "中场取消"
                                            : "未知");
                        })
                        .collect(Collectors.toList());
        return new PageResult<OrderDTO>()
                .setRecords(result)
                .setCurrent(res.getCurrent())
                .setSize(res.getSize())
                .setPages(res.getPages())
                .setTotal(res.getTotal());
    }

    @Override
    public List<String> publishOrderImgs(Long publishOrderId) {
        return publishOrderImgMapper
                .selectList(
                        new QueryWrapper<>(
                                new TPublishOrderImg()
                                        .setPublishOrderId(publishOrderId)))
                .stream()
                .map(m -> StringUtils.isBlank(m.getUrl()) ? null : ossConfig.getHostname() + "/" + m.getUrl())
                .collect(Collectors.toList());
    }


    @Override
    public PageResult<PublishOrderSimple> appPublishOrderList(int pageNo, int pageSize, String mId) {
        Page<Map<String, Object>> publishOrders =
                publishOrderMapper
                        .getFollowPublishOrderBaseInfo(new Page<>(pageNo, pageSize), mId);

        ImmutableMap<Long, TProductCategory> cates = Maps.uniqueIndex(categoryMapper.selectAll(), TProductCategory::getId);
        return new PageResult<PublishOrderSimple>()
                .setCurrent(publishOrders.getCurrent())
                .setPages(publishOrders.getPages())
                .setSize(publishOrders.getSize())
                .setTotal(publishOrders.getTotal())
                .setRecords(publishOrders
                        .getRecords()
                        .stream()
                        .map(m -> {
                            Map<String, String> map =
                                    Maps
                                            .transformEntries(m, (k, v) -> String.valueOf(v));
                            TProductCategory cate = cates.get(Long.parseLong(map.get("category_id")));
                            Map<String, String> identityInfo = DateUtils.computeYearAndConstellation(map.get("identity"));
                            String id = map.get("id");
                            return new PublishOrderSimple()
                                    .setMId(map.get("m_id"))
                                    .setPublishOrderId(id)
                                    .setOtherDesc(map.get("other_desc"))
                                    .setPrice((new BigDecimal(map.get("price")).intValue()) + "")
                                    .setUnit(map.get("unit"))
                                    .setDistance(map.get("distance"))
                                    .setNickName(map.get("nick_name"))
                                    .setImageUrl(StringUtils.isBlank(map.get("img_url")) ? "" : ossConfig.getHostname() + "/" + map.get("img_url"))
                                    .setServiceLevel(map.get("service_level"))
                                    .setImgs(strToList(",", map.get("imgs")))
                                    .setArea(StringUtils.isBlank(map.get("city_name")) ? parseArea(map.get("area")) : map.get("city_name"))
                                    .setShowColor(cate == null ? "" : cate.getShowColor())
                                    .setCategory(cate == null ? "" : cate.getCaption())
                                    .setOnline(DateUtils.computeOnlineTime(DateUtils.localDateTimeOfStr(String.valueOf(map.get("last_visit_time")))))
                                    .setYear(identityInfo.get("year"))
                                    .setConstellation(identityInfo.get("constellation"));
                        })
                        .collect(Collectors.toList())
                );


    }

    @Override
    public ConsumeOrderDetailsDTO consumeOrderDetails(String consumerOrderId, String type) {
        //查询已支付订单信息
        C2cOrder order =
                orderMapper
                        .selectOne(
                                new LambdaQueryWrapper<C2cOrder>()
                                        .select(C2cOrder::getPayTime, C2cOrder::getPublishOrderId, C2cOrder::getMId, C2cOrder::getPayPrice,
                                                C2cOrder::getBeginTime, C2cOrder::getEndTime, C2cOrder::getCommentStatus, C2cOrder::getId,
                                                C2cOrder::getOrderStatus)
                                        .eq(C2cOrder::getId, consumerOrderId)
                                        .eq(C2cOrder::getPayStatus, PayStatusEnum.FINISH.getType())
                        );
        Check.notNull(order, ExpCode.ORDER_NOT_EXIST);

        //支付订单对应的发单信息
        TPublishOrder publishOrder =
                publishOrderMapper
                        .selectOne(
                                new LambdaQueryWrapper<TPublishOrder>()
                                        .select(TPublishOrder::getOtherDesc, TPublishOrder::getMId)
                                        .eq(TPublishOrder::getId, order.getPublishOrderId())
                        );

        C2cOrderItem orderItem =
                orderItemMapper
                        .selectOne(
                                new LambdaQueryWrapper<C2cOrderItem>()
                                        .select(C2cOrderItem::getTips, C2cOrderItem::getShowColor, C2cOrderItem::getUnit, C2cOrderItem::getAmount)
                                        .eq(C2cOrderItem::getC2cOrderId, order.getId())
                        );

        ConsumeOrderDetailsDTO dto = new ConsumeOrderDetailsDTO();

        TMember memberInfo;
        if (AppConst.CAT_CONSUMER_TYPE.equals(type))
            //发单人订单信息 （发单人 看到的用户信息 是下单人的信息）
            memberInfo = memberService.getMemberInfoById(order.getMId() + "");
        else if (AppConst.CAT_SERVICE_TYPE.equals(type))
            //消费者（消费者 看到的用户信息 是发单的信息）
            memberInfo = memberService.getMemberInfoById(publishOrder.getMId() + "");
        else
            throw new ResponseException(ExpCode.PARAMS_UNKNOWN.getCode(), ExpCode.PARAMS_UNKNOWN.getMsg());

        return dto
                .setConsumeOrderId(consumerOrderId)
                .setBeginTime(DateUtils.getLocalDateTimeStr(order.getBeginTime(), AppConst.DATE_SHOW_FORMAT))
                .setEndTime(DateUtils.getLocalDateTimeStr(order.getEndTime(), AppConst.DATE_SHOW_FORMAT))
                .setPayTime(DateUtils.getLocalDateStr(order.getPayTime().toLocalDate()))
                .setPrice(order.getPayPrice().toString())
                .setOrderStatus(order.getOrderStatus() + "")
                .setMId(memberInfo.getId() + "")
                .setImgUrl(memberInfo.getImgUrl())
                .setNickName(memberInfo.getNickName())
                .setOrderContent(publishOrder.getOtherDesc())
                .setCategory(orderItem.getTips())
                .setShowColor(orderItem.getShowColor())
                .setCommentStatus(order.getOrderStatus().equals(AppConst.ORDER_FINISH) &&
                        order.getCommentStatus() == 0 ? "1" : "0")
                .setArea(parseArea(memberInfo.getArea()))
                .setDuration(orderItem.getAmount() + "/" + (orderItem.getUnit().equals(0) ? "小时" : "天"));
    }

    @Transactional
    @Override
    public boolean commentOrder(String orderId, String type, List<String> tag, String mId, String commentContent) {
        C2cOrder order =
                orderMapper
                        .selectOne(new LambdaQueryWrapper<C2cOrder>()
                                .select(C2cOrder::getPayStatus, C2cOrder::getCommentStatus, C2cOrder::getPublishOrderId,
                                        C2cOrder::getMId, C2cOrder::getAutoId)
                                .eq(C2cOrder::getId, orderId)
                                .eq(C2cOrder::getMId, mId)
                                .eq(C2cOrder::getOrderStatus, OrderStatusEnum.FINISH.getStatus())
                        );
        if (order == null || PayStatusEnum.NOT.getType().equals(order.getPayStatus()) || (CommonStatus.NORMAL.getType().equals(order.getCommentStatus())))
            return false;

        TPublishOrder publishOrder =
                publishOrderMapper
                        .selectOne(new LambdaQueryWrapper<TPublishOrder>()
                                .select(TPublishOrder::getAutoId, TPublishOrder::getMId)
                                .eq(TPublishOrder::getId, order.getPublishOrderId())
                        );

        TOrderComment orderComment = new TOrderComment()
                .setMId(order.getMId())
                .setContent(commentContent)
                .setTag(listToStr(tag))
                .setContent(commentContent)
                .setType(Integer.parseInt(type))
                .setCommentMemberId(publishOrder.getMId())
                .setOrderId(Long.parseLong(orderId));
        int commentRow =
                orderCommentMapper
                        .insert(orderComment);

        int orderRow =
                orderMapper
                        .updateById(new C2cOrder()
                                .setAutoId(order.getAutoId())
                                .setCommentStatus(CommonStatus.NORMAL.getType()));
        boolean success = commentRow == 1 && orderRow == 1;
        if (success) {
            taskComponent.pushInteractiveMsg(
                    new InteractiveMsgParams()
                            .setType(SystemMsgEnum.COMMENT.getType())
                            .setId(orderComment.getId().toString())
                            .setMId(mId)
                            .setFromAcc(imConfig.getCommentAcc())
                            .setToAcc(orderComment.getCommentMemberId().toString())
                            .setContent(this.orderComment));
        }
        return success;
    }

    @Override
    public OrderCommentDTO getMemberOrderCommentList(int pageNo, int pageSize, String id) {
        Page<Map<String, Object>> res =
                orderCommentMapper
                        .selectOrderCommentList(
                                new Page<>(pageNo, pageSize),
                                id);
        OrderCommentDTO dto = new OrderCommentDTO();

        dto.
                setTotal(res.getTotal())
                .setPages(res.getPages())
                .setCurrent(res.getCurrent())
                .setSize(res.getSize())
                .setList(
                        res
                                .getRecords()
                                .stream()
                                .map(m -> {
                                    Map<String, String> map = Maps.transformEntries(m, (k, v) -> String.valueOf(v));

                                    if (dto.getNiceScale() == null)
                                        dto.setNiceScale(
                                                (new BigDecimal(map.get("nice_scale"))
                                                        .divide(new BigDecimal(map.get("total")), 2, BigDecimal.ROUND_HALF_UP)
                                                        .multiply(AppConst.b100)).intValue());

                                    return new OrderCommentDTO()
                                            .setNickName(map.get("nick_name"))
                                            .setImgUrl(StringUtils.isBlank(map.get("img_url")) ? null : ossConfig.getHostname() + "/" + map.get("img_url"))
                                            .setTag(strToList(",", map.get("tag")))
                                            .setCommentContent(map.get("content"))
                                            .setType(map.get("c_type"));
                                })
                                .collect(Collectors.toList())
                );


        return dto;
    }

    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    @Override
    public boolean editPublishOrderInfo(String mId, String publishOrderId, String price,
                                        String ageLimit, String genderLimit,
                                        List<String> timeLimit, String otherDesc, List<String> url) {
        int orderRow =
                publishOrderMapper
                        .update(null, new LambdaUpdateWrapper<TPublishOrder>()
                                .set(StringUtils.isNotBlank(ageLimit), TPublishOrder::getAgeLimit, ageLimit)
                                .set(CollectionUtils.isNotEmpty(timeLimit), TPublishOrder::getTimeLimit, listToStr(timeLimit))
                                .set(StringUtils.isNotBlank(genderLimit), TPublishOrder::getGenderLimit, genderLimit)
                                .set(StringUtils.isNotBlank(otherDesc), TPublishOrder::getOtherDesc, otherDesc)
                                .set(StringUtils.isNotBlank(price), TPublishOrder::getPrice, price)
                                .set(TPublishOrder::getStatus, PublishOrderEnum.NORMAL.getStatus())
                                .eq(TPublishOrder::getId, publishOrderId)
                                .eq(TPublishOrder::getMId, mId)
                        );

        if (CollectionUtils.isNotEmpty(url) && orderRow > 0) {
            publishOrderImgMapper
                    .delete(new LambdaQueryWrapper<TPublishOrderImg>()
                            .eq(TPublishOrderImg::getPublishOrderId, publishOrderId));

            publishOrderImgMapper
                    .insertBatchSomeColumn(
                            url
                                    .stream()
                                    .map(m ->
                                            new TPublishOrderImg()
                                                    .setPublishOrderId(Long.parseLong(publishOrderId))
                                                    .setUrl(StringUtils.isBlank(m) ? m : m.replace(ossConfig.getHostname() + "/", ""))
                                                    .setAddTime(new Date())
                                    ).collect(Collectors.toList()));
        }

        return orderRow == 1;
    }


    @Override
    public C2cOrder getC2cOrderInfoById(String id) {
        return orderMapper.selectOne(
                new QueryWrapper<>(
                        new C2cOrder().setId(id))
        );
    }

    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    @Override
    public boolean confirmOrder(final String mId, final String id) {
        //查询已支付订单信息
        final C2cOrder order =
                orderMapper
                        .selectOne(
                                new LambdaQueryWrapper<C2cOrder>()
                                        .select(C2cOrder::getPayPrice, C2cOrder::getProductPrice, C2cOrder::getOrderStatus,
                                                C2cOrder::getPublishOrderId, C2cOrder::getRefundStatus, C2cOrder::getTransactionId)
                                        .eq(C2cOrder::getId, id)
                                        .eq(C2cOrder::getMId, mId)
                                        .eq(C2cOrder::getPayStatus, PayStatusEnum.FINISH.getType())
                        );

        //订单状态不是已完成 || 处于退款状态
        if (order == null
                || AppConst.ORDER_FINISH.equals(order.getOrderStatus())
                || AppConst.ORDER_REFUND_FINISH.equals(order.getRefundStatus()))
            return false;

        //查询发单信息
        TPublishOrder publishOrder =
                publishOrderMapper
                        .selectOne(new LambdaQueryWrapper<TPublishOrder>()
                                .select(TPublishOrder::getMId, TPublishOrder::getSellCount)
                                .eq(TPublishOrder::getId, order.getPublishOrderId())
                        );
        if (publishOrder == null) return false;

        Long serviceMemberId = publishOrder.getMId();
        TMember memberInfo = memberService.getMemberMoneyInfo(serviceMemberId);
        if (memberInfo == null) return false;

        TScaleSetting setting = scaleSettingMapper.selectOne(new QueryWrapper<>(new TScaleSetting().setType(OrderScaleEnum.PUBLISH_ORDER.getType())));
        BigDecimal orderScale = BigDecimal.ZERO;
        if (setting != null && setting.getScale().doubleValue() > 0)
            orderScale = setting.getScale();
        //抽成比例大于0 进行抽成否者不进行
        Boolean action = orderScale.doubleValue()>0;
        final BigDecimal payPrice = order.getPayPrice();
        //平台抽成 COMPANY_ORDER_SCALE 比例
        BigDecimal companyGrain =action? payPrice.multiply(orderScale):BigDecimal.ZERO;
        //发单人资金 = 支付价格- 平台抽成
        final BigDecimal memberGain = payPrice.subtract(companyGrain);

        Long version = memberInfo.getVersion();
        final BigDecimal memberInfoBalance = memberInfo.getBalance();
        final BigDecimal balance = memberInfoBalance.add(memberGain);
        BigDecimal spreadProfit = BigDecimal.ZERO;
        BigDecimal scale = BigDecimal.ZERO;

        //处理推广
//        Long parentId = memberInfo.getParentId();
//        if (parentId != null && parentId > 0) {
//            Integer serviceCount = memberMapper.selectCount(
//                    new LambdaQueryWrapper<TMember>()
//                            .eq(TMember::getParentId, parentId)
//                            .ge(TMember::getIdStatus, CommonStatus.NORMAL.getType()));
//            scale = tSpreadSettingMapper.selectList(null)
//                    .stream()
//                    .filter(f -> f.getConditions() <= serviceCount)
//                    .map(TSpreadSetting::getScale)
//                    .max(BigDecimal::compareTo)
//                    .orElse(BigDecimal.ZERO);
//
//            if (scale.compareTo(BigDecimal.ZERO) > 0) {
//                //推广盈利收益比例大于 0 进行推广利润加成
//                TMember spreadMemberInfo = memberMapper
//                        .selectOne(
//                                new LambdaQueryWrapper<TMember>()
//                                        .select(TMember::getAutoId, TMember::getId, TMember::getBalance, TMember::getConsumeMoney, TMember::getOperateMoney,
//                                                TMember::getRechargeMoney, TMember::getIncomeMoney, TMember::getPopularMoney, TMember::getVersion, TMember::getParentId)
//                                        .eq(TMember::getAutoId, parentId)
//                        );
//                if (spreadMemberInfo != null) {
//                    Long spreadVersion = spreadMemberInfo.getVersion();
//                    BigDecimal spreadMoney = spreadMemberInfo.getBalance();
//                    spreadProfit = payPrice.multiply(scale.divide(AppConst.b100, 4));
//                    BigDecimal spreadBalance = spreadMoney.add(spreadProfit);
//                    //推广佣金 分成占比 由公司抽成金额扣减
//                    // companyGrain = companyGrain.subtract(spreadProfit);
//                    //推广盈利金额入账
//                    int memberRow =
//                            memberMapper
//                                    .update(null,
//                                            new LambdaUpdateWrapper<TMember>()
//                                                    .set(TMember::getBalance, spreadBalance)
//                                                    .set(TMember::getVersion, spreadVersion + 1)
//                                                    .set(TMember::getIncomeMoney, spreadMemberInfo.getIncomeMoney().add(spreadProfit))
//                                                    .eq(TMember::getId, spreadMemberInfo.getId())
//                                                    .eq(TMember::getVersion, spreadVersion)
//                                    );
//
//                    //金额日志记录
//                    int logRow = memberBalanceLogMapper.insert(
//                            new TMemberBalanceLog()
//                                    .setStatus(CommonStatus.NORMAL.getType())
//                                    .setMId(spreadMemberInfo.getId())
//                                    .setPayTime(LocalDateTime.now())
//                                    .setTips(BalanceLogEnum.SPREAD_PROFIT.getTips())
//                                    .setTradeType(BalanceLogEnum.SPREAD_PROFIT.getType())
//                                    .setMethod(Integer.parseInt(PaymentEnum.SYSTEM_PAY.getType()))
//                                    .setTradeNo(id)
//                                    .setTransactionId(order.getTransactionId())
//                                    .setBeforeM(spreadMoney)
//                                    .setMoney(spreadProfit)
//                                    .setFee(BigDecimal.ZERO)
//                                    .setFeeScale(scale.divide(AppConst.b100, 3, 4).toString())
//                                    .setBalance(spreadBalance)
//                    );
//
//                }
//            }
//        }


        //发单人金额入账
        int memberRow =
                memberMapper
                        .update(null,
                                new LambdaUpdateWrapper<TMember>()
                                        .set(TMember::getBalance, balance)
                                        .set(TMember::getVersion, version + 1)
                                        .set(TMember::getIncomeMoney, memberInfo.getIncomeMoney().add(memberGain))
                                        .eq(TMember::getId, serviceMemberId)
                                        .eq(TMember::getVersion, version)
                        );

        //金额日志记录
        int logRow = memberBalanceLogMapper.insert(
                new TMemberBalanceLog()
                        .setStatus(CommonStatus.NORMAL.getType())
                        .setMId(serviceMemberId)
                        .setPayTime(LocalDateTime.now())
                        .setTips(BalanceLogEnum.FINISH_ORDER.getTips())
                        .setTradeType(BalanceLogEnum.FINISH_ORDER.getType())
                        .setMethod(Integer.parseInt(PaymentEnum.SYSTEM_PAY.getType()))
                        .setTradeNo(id)
                        .setTransactionId(order.getTransactionId())
                        .setBeforeM(memberInfoBalance)
                        .setMoney(memberGain)
                        .setFee(companyGrain)
                        .setFeeScale(orderScale.stripTrailingZeros().toPlainString())
                        .setBalance(balance)
        );
        //修改订单状态 -> 已完成
        int orderRow =
                orderMapper
                        .update(null,
                                new LambdaUpdateWrapper<C2cOrder>()
                                        .set(C2cOrder::getOrderStatus, AppConst.ORDER_FINISH)
                                        .eq(C2cOrder::getId, id)
                        );
        if (!(memberRow == 1 && orderRow == 1 && logRow == 1)) {
            logger.error("confirm order err --> orderId{}", id);
            throw new ServiceException("完成订单失败");
        }
        TOrderSplit orderSplit = new TOrderSplit()
                .setC2cOrderId(Long.parseLong(id))
                .setCompanyCommission(action?companyGrain.subtract(spreadProfit):BigDecimal.ZERO)
                .setMemberCommission(memberGain)
                .setOriginOrderPrice(order.getProductPrice())
                .setRealPrice(payPrice)
                .setOrderType(OrderSplitEnum.SERVICE_ORDER.getType())
                .setSpreadMoney(spreadProfit)
                .setSpreadScale(scale);

        //asyncTask  记录订单分账日志
        CompletableFuture
                .runAsync(() -> {
                    int row =
                            orderSplitMapper
                                    .insert(orderSplit);
                    if (row != 1)
                        logger.error("分账信息添加失败 orderId:{},company:{},member:{},payPrice:{},origin:", id, companyGrain, memberGain, payPrice, order.getProductPrice());

                    TMember consumeMember = memberService.getMemberMoneyInfo(Long.parseLong(mId));
                    BigDecimal consumeMoney = consumeMember.getConsumeMoney().add(payPrice);
                    Long versionC = consumeMember.getVersion();
                    row =
                            memberMapper
                                    .update(null,
                                            new LambdaUpdateWrapper<TMember>()
                                                    .set(TMember::getConsumeMoney, consumeMoney)
                                                    .set(TMember::getVersion, versionC + 1)
                                                    .eq(TMember::getId, mId)
                                                    .eq(TMember::getVersion, versionC)
                                    );
                    if (row != 1)
                        logger.error("总消费数据修改失败 mId:{},orderId:{},payPrice:{}", mId, id, payPrice);

                    //订单销售次数 修改
                    Integer sellCount = publishOrder.getSellCount();
                    row =
                            publishOrderMapper
                                    .update(
                                            null,
                                            new LambdaUpdateWrapper<TPublishOrder>()
                                                    .set(TPublishOrder::getSellCount, sellCount + 1)
                                                    .eq(TPublishOrder::getId, order.getPublishOrderId())
                                                    .eq(TPublishOrder::getSellCount, sellCount)

                                    );
                    if (row != 1)
                        logger.error("修改销售数量失败 publish order:{},orderId:{}", order.getPublishOrderId(), id);

                }, executor);
        //   redis.delStrKey(RedisListenerEnum.auto_confirm_order.getKey() + RedisListenerEnum.split + id);
        return true;
    }

    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    @Override
    public boolean cancelOrder(final String mId, final String id, String reason) {
        //要取消的订单信息
        C2cOrder order =
                orderMapper
                        .selectOne(
                                new QueryWrapper<>(
                                        new C2cOrder().setId(id))
                        );

        if (order == null)
            throw new ResponseException(ExpCode.ORDER_NOT_EXIST.getCode(), ExpCode.ORDER_NOT_EXIST.getMsg());

        //取消请求发起人不是该下单人|订单状态不是支付状态 | 未接单，已接单  状态
        if (!order.getMId().equals(Long.parseLong(mId)) || order.getOrderStatus() >= OrderStatusEnum.FINISH.getStatus() || PayStatusEnum.NOT.getType().equals(order.getPayStatus()))
            throw new ResponseException(ExpCode.ORDER_INFO_ERR.getCode(), ExpCode.ORDER_INFO_ERR.getMsg());

        //检查该会员当天取消的订单次数
        Integer cancelCount =
                orderCancelMapper
                        .selectCount(new LambdaQueryWrapper<C2cOrderCancel>()
                                .eq(C2cOrderCancel::getMId, mId)
                                .last("and to_days(cancel_time) = to_days(sysdate())"));
        //一天最大限制 2 次取消次数
        if (cancelCount >= balanceConfig.getCancelMax())
            throw new ResponseException(ExpCode.ORDER_CANCEL_MAX.getCode(), ExpCode.ORDER_CANCEL_MAX.getMsg());

        //会员信息获取
        TMember member = memberMapper
                .selectOne(
                        new LambdaQueryWrapper<TMember>()
                                .select(TMember::getVersion, TMember::getDd, TMember::getBalance)
                                .eq(TMember::getId, mId)
                                .eq(TMember::getStatus, MemberStatusEnum.NORMAL.getCode())
                );
        BigDecimal cancelScale = BigDecimal.ZERO;
        BigDecimal cancelFee = BigDecimal.ZERO;
        Check.notNull(member, ExpCode.LOGIN_INFO_ERR);


        //订单支付价格
        BigDecimal payPrice = order.getPayPrice();
        //优惠价格
        BigDecimal couponPrice = order.getCouponPrice();
        Integer couponStatus = order.getCouponStatus();


        if (order.getMId().toString().equals(mId)) {
            TScaleSetting tScaleSetting = scaleSettingMapper.selectOne(new QueryWrapper<>(new TScaleSetting().setType(OrderScaleEnum.PUBLISH_ORDER_CANCEL.getType())));
            cancelScale = Optional.ofNullable(tScaleSetting).map(TScaleSetting::getScale).orElse(new BigDecimal(OrderScaleEnum.PUBLISH_ORDER_CANCEL.getDefScale()));
            cancelFee = payPrice.multiply(cancelScale).setScale(2, 5);
            payPrice = payPrice.subtract(cancelFee);
        }

        //会员余额
        BigDecimal balance = member.getBalance();
        Integer dd = member.getDd();
        //数据版本
        Long mver = member.getVersion();
        BigDecimal newBalance = balance.add(payPrice);
        Integer newDD = dd + (couponPrice == null ? 0 : couponPrice.multiply(AppConst.b100)).intValue();


        //修改会员余额 优惠
        int row = memberMapper.update(
                null,
                new LambdaUpdateWrapper<TMember>()
                        .set(TMember::getBalance, newBalance)
                        .set(TMember::getDd, newDD)
                        .set(TMember::getVersion, mver + 1)
                        .eq(TMember::getId, mId)
                        .eq(TMember::getVersion, mver)
        );
        if (row == 1) {
            //备份取消订单信息
            C2cOrderCancel cancel = new C2cOrderCancel();
            BeanUtils.copyProperties(order, cancel);
      //      BeanUtils.copyProperties(order, cancel);
            cancel.setCancelReason(reason)
                    .setHandleTime(LocalDateTime.now())
                    .setCancelTime(LocalDateTime.now());
            int cancelRow = orderCancelMapper.insert(cancel);
            //删除订单
            int delRow = orderMapper.delete(new QueryWrapper<>(new C2cOrder().setId(id)));
            int delItemRow = orderItemMapper.delete(new QueryWrapper<>(new C2cOrderItem().setC2cOrderId(id)));
            //余额日志添加
            int logRow = memberBalanceLogMapper
                    .insert(
                            new TMemberBalanceLog()
                                    .setTradeNo(id)
                                    .setTradeType(BalanceLogEnum.CANCEL_ORDER.getType())
                                    .setBeforeM(balance)
                                    .setMoney(payPrice)
                                    .setPrePayId(order.getPrePayId())
                                    .setTransactionId(order.getTransactionId())
                                    .setBalance(newBalance)
                                    .setMethod(Integer.parseInt(PaymentEnum.SYSTEM_PAY.getType()))
                                    .setTips(BalanceLogEnum.CANCEL_ORDER.getTips())
                                    .setPayTime(LocalDateTime.now())
                                    .setMId(Long.parseLong(mId))
                                    .setFee(cancelFee)
                                    .setFeeScale(cancelScale.stripTrailingZeros().toPlainString())
                                    .setStatus(CommonStatus.NORMAL.getType())
                    );
            //存在有优惠记录 --删除
            if (AppConst.COUPON_DD.equals(couponStatus) && couponPrice != null && couponPrice.compareTo(BigDecimal.ZERO) > 0)
                ddLogMapper.delete(new QueryWrapper<>(new TDdLog().setMId(Long.parseLong(mId)).setTradeNo(id).setTradeNo("0")));

            if (cancelRow != 1 || delRow != 1 || logRow != 1)
                throw new RuntimeException("取消订单 更新数据失败");
            taskComponent.updPublishCancelCount(order.getPublishOrderId());
        }
        return true;

    }

    @Override
    public boolean delPublishOrder(String mId, String id) {
        return publishOrderMapper
                .update(
                        null,
                        new LambdaUpdateWrapper<TPublishOrder>()
                                .set(TPublishOrder::getStatus, PublishOrderEnum.DEL.getStatus())
                                .eq(TPublishOrder::getId, id)
                                .eq(TPublishOrder::getMId, mId)
                ) == 1;
    }

    @Override
    public EditPublishOrderDTO editPublishOrderShowData(String mId, String id) {
        TPublishOrder publishOrder = publishOrderMapper
                .selectOne(
                        new LambdaQueryWrapper<TPublishOrder>()
                                .select(TPublishOrder::getPrice, TPublishOrder::getOtherDesc, TPublishOrder::getUnit, TPublishOrder::getAgeLimit,
                                        TPublishOrder::getGenderLimit, TPublishOrder::getTimeLimit, TPublishOrder::getPrice)
                                .eq(TPublishOrder::getId, id)
                                .eq(TPublishOrder::getMId, mId)

                );
        Check.notNull(publishOrder, ExpCode.ORDER_NOT_EXIST);

        return new EditPublishOrderDTO()
                .setPublishOrderId(id)
                .setMId(mId)
                .setAgeLimit(publishOrder.getAgeLimit())
                .setGenderLimit(publishOrder.getGenderLimit())
                .setContent(publishOrder.getOtherDesc())
                .setPrice(publishOrder.getPrice().toString())
                .setUnit(publishOrder.getUnit())
                .setUrl(publishOrderImgs(Long.parseLong(id)))
                .setTimeSelectors(strToList(",", publishOrder.getTimeLimit())
                        .stream()
                        .filter(f -> StringUtils.isNotBlank(f) && Pattern.matches(AppConst.PUBLISH_ORDER_TIME, f))
                        .map(m -> {
                            String[] timeLimit = m.split("_");
                            return new EditPublishOrderDTO().getTimeSelector()
                                    .setWeekNum(timeLimit[0])
                                    .setWeekStr(WeekTips.getStr(Integer.parseInt(timeLimit[0])))
                                    .setBeginTime(timeLimit[1].split("-")[0])
                                    .setEndTIme(timeLimit[1].split("-")[1]);

                        })
                        .collect(Collectors.toList())
                );

    }

    @Override
    public PageResult<Map> catMemberPublishOrderList(int pageNo, int pageSize, String target) {
        TMember member = memberMapper.selectOne(
                new LambdaQueryWrapper<TMember>()
                        .select(TMember::getEnableOrder)
                        .eq(TMember::getId, target)
        );
        //查看目标用户  是否开启查看订单权限
        if (member == null || CommonStatus.DISABLED.getType().equals(member.getEnableOrder()))
            return new PageResult<>();

        Page<TPublishOrder> publishOrderPage =
                publishOrderMapper
                        .selectPage(
                                new Page<>(pageNo, pageSize),
                                new LambdaQueryWrapper<TPublishOrder>()
                                        .select(TPublishOrder::getId, TPublishOrder::getOtherDesc, TPublishOrder::getMId, TPublishOrder::getAreaLimit,
                                                TPublishOrder::getUnit, TPublishOrder::getPrice, TPublishOrder::getCategoryId, TPublishOrder::getAddTime)
                                        .eq(TPublishOrder::getMId, target)
                                        .eq(TPublishOrder::getStatus, PublishOrderEnum.NORMAL.getStatus())
                                        .orderByDesc(TPublishOrder::getAddTime)
                        );
        List<String> ids =
                publishOrderPage
                        .getRecords()
                        .stream()
                        .map(TPublishOrder::getId)
                        .collect(Collectors.toList());

        if (CollectionUtils.isEmpty(ids))
            return new PageResult<>();

        ImmutableMap<Long, TProductCategory> cateMap =
                Maps.uniqueIndex(categoryMapper.selectAll(), TProductCategory::getId);

        // key = publishorderid, value = 发单所有附件信息
        Map<Long, List<TPublishOrderImg>> imgMaps =
                publishOrderImgMapper
                        .selectList(
                                new LambdaQueryWrapper<TPublishOrderImg>()
                                        .select(TPublishOrderImg::getUrl, TPublishOrderImg::getPublishOrderId)
                                        .in(TPublishOrderImg::getPublishOrderId, ids))
                        .stream()
                        .filter(f -> f.getPublishOrderId() != null && StringUtils.isNotBlank(f.getUrl()))
                        .map(m -> m.setUrl(ossConfig.getHostname() + "/" + m.getUrl()))
                        .collect(Collectors.groupingBy(TPublishOrderImg::getPublishOrderId));


        return new PageResult<Map>()
                .setSize(publishOrderPage.getSize())
                .setCurrent(publishOrderPage.getCurrent())
                .setTotal(publishOrderPage.getTotal())
                .setPages(publishOrderPage.getPages())
                .setRecords(
                        publishOrderPage
                                .getRecords()
                                .stream()
                                .map(m -> {
                                            long mId = Long.parseLong(m.getId());
                                            Map<String, Object> map = new HashMap<>();
                                            map.put("publishOrderId", m.getId());
                                            map.put("otherDesc", m.getOtherDesc());
                                            map.put("date", DateUtils.getLocalDateTimeStr(m.getAddTime(), "MM-dd HH:mm"));
                                            map.put("imgs", imgMaps.get(mId) == null ? new ArrayList<>() :
                                                    imgMaps.get(mId)
                                                            .stream()
                                                            .filter(f -> StringUtils.isNoneBlank(f.getUrl()))
                                                            .map(TPublishOrderImg::getUrl)
                                                            .collect(Collectors.toList()));
                                            map.put("category", cateMap.get(m.getCategoryId()) == null ? "" : cateMap.get(m.getCategoryId()).getCaption());
                                            map.put("showColor", cateMap.get(m.getCategoryId()) == null ? "" : cateMap.get(m.getCategoryId()).getShowColor());
                                            return map;
                                        }
                                )
                                .collect(Collectors.toList())
                );
    }

    @Transactional(rollbackFor = Throwable.class)
    @Override
    public void cancelNotProcessTimeOutOrder(final String orderId) {
        if (StringUtils.isBlank(orderId))
            return;
        //查询订单  满足条件 支付状态->已支付 &订单状态->未处理
        C2cOrder order = orderMapper
                .selectOne(
                        new LambdaQueryWrapper<C2cOrder>()
                                //.select(C2cOrder::getCouponPrice, C2cOrder::getMId, C2cOrder::getCouponStatus, C2cOrder::getPayPrice)
                                .eq(C2cOrder::getId, orderId)
                                .eq(C2cOrder::getPayStatus, PayStatusEnum.FINISH.getType())
                                .eq(C2cOrder::getOrderStatus, OrderStatusEnum.AWAIT.getStatus())
                );
        if (order == null)
            return;
        final Long mId = order.getMId();
        //会员信息获取
        TMember member = memberMapper
                .selectOne(
                        new LambdaQueryWrapper<TMember>()
                                .select(TMember::getVersion, TMember::getDd, TMember::getBalance)
                                .eq(TMember::getId, mId)
                                .eq(TMember::getStatus, MemberStatusEnum.NORMAL.getCode())
                );
        if (member == null)
            return;

        //订单支付价格
        BigDecimal payPrice = order.getPayPrice();
        //优惠价格
        BigDecimal couponPrice = order.getCouponPrice();
        Integer couponStatus = order.getCouponStatus();
        //会员余额
        BigDecimal balance = member.getBalance();
        Integer dd = member.getDd();
        //数据版本
        Long mver = member.getVersion();
        BigDecimal newBalance = balance.add(payPrice);
        Integer newDD = dd + (couponPrice == null ? 0 : couponPrice.multiply(AppConst.b100)).intValue();

        //修改会员余额 优惠
        int row = memberMapper.update(
                null,
                new LambdaUpdateWrapper<TMember>()
                        .set(TMember::getBalance, newBalance)
                        .set(TMember::getDd, newDD)
                        .set(TMember::getVersion, mver + 1)
                        .eq(TMember::getId, mId)
                        .eq(TMember::getVersion, mver)
        );
        if (row == 1) {
            //备份取消订单信息
            C2cOrderCancel cancel = new C2cOrderCancel();
            BeanUtils.copyProperties(order, cancel);
          //  BeanUtils.copyProperties(order, cancel);
            cancel.setCancelReason("超时未接单-自动取消")
                    .setHandleTime(LocalDateTime.now())
                    .setCancelTime(LocalDateTime.now());
            int cancelRow = orderCancelMapper.insert(cancel);
            //删除订单
            int delRow = orderMapper.delete(new QueryWrapper<>(new C2cOrder().setId(orderId)));
            int delItemRow = orderItemMapper.delete(new QueryWrapper<>(new C2cOrderItem().setC2cOrderId(orderId)));
            //余额日志添加
            int logRow = memberBalanceLogMapper
                    .insert(
                            new TMemberBalanceLog()
                                    .setTradeNo(orderId)
                                    .setTradeType(BalanceLogEnum.CANCEL_ORDER.getType())
                                    .setBeforeM(balance)
                                    .setMoney(payPrice)
                                    .setPrePayId(order.getPrePayId())
                                    .setTransactionId(order.getTransactionId())
                                    .setBalance(newBalance)
                                    .setMethod(Integer.parseInt(PaymentEnum.SYSTEM_PAY.getType()))
                                    .setTips(BalanceLogEnum.CANCEL_ORDER.getTips())
                                    .setPayTime(LocalDateTime.now())
                                    .setMId(mId)
                                    .setStatus(CommonStatus.NORMAL.getType())
                    );
            //存在有优惠记录 --删除
            if (AppConst.COUPON_DD.equals(couponStatus) && couponPrice != null && couponPrice.compareTo(BigDecimal.ZERO) > 0) {
                ddLogMapper.delete(new QueryWrapper<>(new TDdLog().setMId(mId).setTradeNo(orderId).setTradeNo("0")));
            }
            if (cancelRow != 1 || delRow != 1 || logRow != 1)
                throw new RuntimeException("自动取消订单 更新数据失败");
            taskComponent.updPublishCancelCount(order.getPublishOrderId());
        }

    }


    @Transactional(rollbackFor = Throwable.class)
    @Override
    public void cancelTimeOutOrder(String orderId) {
        if (StringUtils.isBlank(orderId))
            return;
        C2cOrder order = orderMapper
                .selectOne(
                        new LambdaQueryWrapper<C2cOrder>()
                                .select(C2cOrder::getCouponPrice, C2cOrder::getMId)
                                .eq(C2cOrder::getId, orderId)
                                .eq(C2cOrder::getPayStatus, PayStatusEnum.NOT.getType())
                );
        if (order == null)
            return;
        Long mId = order.getMId();
        TMember member = memberMapper.selectOne(
                new LambdaQueryWrapper<TMember>()
                        .select(TMember::getDd, TMember::getVersion)
                        .eq(TMember::getId, mId)
        );
        if (order.getCouponPrice().compareTo(BigDecimal.ZERO) > 0) {
            //未支付订单优惠 返用户
            int row = memberMapper.update(
                    null,
                    new LambdaUpdateWrapper<TMember>()
                            .set(TMember::getDd, member.getDd() + (order.getCouponPrice().multiply(BigDecimal.valueOf(100)).intValue()))
                            .set(TMember::getVersion, member.getVersion() + 1)
                            .eq(TMember::getId, mId)
                            .eq(TMember::getVersion, member.getVersion())
            );
            if (row == 1) {
                //删除超时未支付订单
                orderMapper.delete(
                        new QueryWrapper<>(
                                new C2cOrder()
                                        .setId(orderId)
                                        .setPayStatus(PayStatusEnum.NOT.getType()).setMId(mId)));
                orderItemMapper.delete(
                        new QueryWrapper<>(
                                new C2cOrderItem()
                                        .setC2cOrderId(orderId)));


            } else
                logger.error("未支付订单取消 优惠退回失败.id::{},coupon::{}", orderId, order.getCouponPrice());


        }

    }

    @Override
    public OrderAwaitCountDTO getAwaitProcessOrderCount(String mId) {

        List<OrderStatusDTO> orderStatusCount = orderMapper.selectOrderStatusCount(mId);
        List<OrderStatusDTO> publishStatusCount = orderMapper.selectPublishOrderStatusCount(mId);
        //派单申请接单待处理数量
        Integer dispatchApplyAwaitCount = applyMapper.selectCount(
                new LambdaQueryWrapper<TDispatchOrderApply>()
                        .eq(TDispatchOrderApply::getApplyMId, mId)
                        .eq(TDispatchOrderApply::getStatus, CommonStatus.NORMAL.getType())
        );
        Integer dispatchOrderAwaitCount = dispatchOrderMapper.selectCount(
                new LambdaQueryWrapper<TDispatchOrder>()
                        .eq(TDispatchOrder::getMId, mId)
                        .eq(TDispatchOrder::getStatus, DispatchOrderStatusEnum.await.getStatus())
        );

        Integer dispatchOrderProcessingCount = dispatchOrderMapper
                .selectCount(
                        new LambdaQueryWrapper<TDispatchOrder>()
                                .eq(TDispatchOrder::getStatus, DispatchOrderStatusEnum.processing.getStatus())
                                .and(and -> and.eq(TDispatchOrder::getMId, mId).or(or -> or.eq(TDispatchOrder::getServiceId, mId)))
                );

        Integer commentCount = orderMapper.selectCount(
                new LambdaQueryWrapper<C2cOrder>()
                        .eq(C2cOrder::getMId, mId)
                        .eq(C2cOrder::getPayStatus, PayStatusEnum.FINISH.getType())
                        .eq(C2cOrder::getOrderStatus, OrderStatusEnum.FINISH.getStatus())
                        .eq(C2cOrder::getCommentStatus, CommonStatus.DISABLED.getType()));
        Integer await = orderStatusCount.stream().filter(f -> OrderStatusEnum.AWAIT.getStatus().equals(f.getStatus())).map(OrderStatusDTO::getNum).reduce(0, Integer::sum);
        Integer process = orderStatusCount.stream().filter(f -> OrderStatusEnum.PROCESS.getStatus().equals(f.getStatus())).map(OrderStatusDTO::getNum).reduce(0, Integer::sum);
        Integer buyItCount = publishStatusCount.stream().filter(f -> OrderStatusEnum.AWAIT.getStatus().equals(f.getStatus())).map(OrderStatusDTO::getNum).reduce(await, Integer::sum);
        Integer ProcessCount = publishStatusCount.stream().filter(f -> OrderStatusEnum.PROCESS.getStatus().equals(f.getStatus())).map(OrderStatusDTO::getNum).reduce(process, Integer::sum);
        return new OrderAwaitCountDTO()
                .setCommentCount(commentCount)
                .setBuyItCount(buyItCount + dispatchOrderAwaitCount + dispatchApplyAwaitCount)
                .setServiceCount(ProcessCount + dispatchOrderProcessingCount);
    }

    @Override
    public String getMIdByOrderId(String id) {
        C2cOrder order = orderMapper.selectOne(new LambdaQueryWrapper<C2cOrder>()
                .select(C2cOrder::getMId)
                .eq(C2cOrder::getId, id));
        Check.notNull(order, ExpCode.ORDER_NOT_EXIST);
        return String.valueOf(order.getMId());
    }

    @Override
    public boolean hidePublishOrder(String mId, String orderId) {
        return publishOrderMapper
                .update(
                        null,
                        new LambdaUpdateWrapper<TPublishOrder>()
                                .set(TPublishOrder::getStatus, PublishOrderEnum.HIDE.getStatus())
                                .eq(TPublishOrder::getId, orderId)
                                .eq(TPublishOrder::getMId, mId)
                ) == 1;
    }

    @Override
    public Boolean existsPublishOrder(String id) {
        return publishOrderMapper
                .selectCount(
                        new LambdaUpdateWrapper<TPublishOrder>()
                                .eq(TPublishOrder::getMId, id)
                ) > 0;

    }

    @Override
    public Boolean existsBuyItOrder(String id) {
        return orderMapper.selectCount(
                new LambdaQueryWrapper<C2cOrder>()
                        .eq(C2cOrder::getMId, id)
                        .eq(C2cOrder::getPayStatus, PayStatusEnum.FINISH.getType())

        ) > 0;
    }

    @Override
    public boolean checkPublishOrder(Long mId) {
        LocalDateTime time = LocalDateTime.of(LocalDate.now(), LocalTime.MIN);

        Integer publishCount = publishOrderMapper.selectCount(
                new LambdaQueryWrapper<TPublishOrder>()
                        .eq(TPublishOrder::getMId, mId)
                        .eq(TPublishOrder::getStatus, CommonStatus.NORMAL.getType())
                        .ge(TPublishOrder::getAddTime, time)
        );
        return publishCount == 0;
    }

    private void recordHistory(String mId, String orderId) {
        if (StringUtils.isBlank(mId) || StringUtils.isBlank(orderId))
            return;
        String key = CacheKey.USER.userHistory + mId;
        long score = BigDecimal.valueOf(System.currentTimeMillis()).negate().longValue();
        redis.zAdd(key, score, orderId);
        redis.zremrangeByScore(key, score + (7 * (84375 << 10)), 1);
    }


}
